home *** CD-ROM | disk | FTP | other *** search
/ Beginning Mac Programming / Beginning Mac Programming.bin / Open Me for REALbasic 3 / REALbasic 3.2 / Example Projects / Reusable Classes_Code / User Interface / KeyCanvas Plugin a1 / KeyCanvas Source / KeyCanvas.cpp < prev    next >
Text File  |  2000-01-06  |  28KB  |  1,046 lines

  1. /*
  2.  
  3. KeyCanvas Plugin
  4.  
  5. Version:     1.0
  6.  
  7. Date:    January 1, 2000 (Happy New Mille...uh, Year!)
  8.  
  9. __Contact__
  10. author:    Doug Holton
  11. email:    doug.holton@vanderbilt.edu
  12. web:    http://www.playground.ltc.vanderbilt.edu/~holtondl/basic/
  13.  
  14. __Notes__
  15. ***    This code is not very well commented.  Please email me any questions you
  16. have about any part of the source, no matter how "newbie" you think your
  17. question is.  Especially since there is virtually no documentation on
  18. Realbasic plugin programming.
  19.  
  20. ***    If you know ways to improve or extend the capabilities of this plugin,
  21. fix bugs, or you have the CW libraries for x86 installed and can add the DLL
  22. resource to the plugin, feel free to make any changes you like.  
  23. Please send it my way so this plugin can be updated and you will be credited.
  24.  
  25.  
  26. *** The ScrollBar functions were copied from K.J. Bricknell's great Macintosh-C
  27. tutorial at http://www.mactech.com/macintosh-c/
  28.  
  29. *** The skeleton of the source was adapted from Erich Tejkowski's MacTech
  30.     sample control plugin, and moved to Thomas Tempelmann's sample plugin CW project.
  31. */
  32.  
  33. #include "rb_plugin.h"
  34.  
  35. #include <Appearance.h>
  36. #include <Processes.h>
  37. #include <Controls.h>
  38. #include <Quickdraw.h>
  39.  
  40. //scrollbar callback functions:
  41. ControlActionUPP    actionFunctionVertUPP;
  42. ControlActionUPP    actionFunctionHorizUPP;
  43.  
  44. Boolean             gHasAppearance = false;
  45. Boolean                gHaveOpened = false;
  46.  
  47. //other user functions:
  48. static void MyControlRect(REALcontrolInstance instance, Rect *rBounds);
  49. static Boolean notinIDE(REALcontrolInstance instance);
  50. static void CreateVScroll(REALcontrolInstance instance);
  51. static void CreateHScroll(REALcontrolInstance instance);
  52.  
  53. pascal void actionFunctionVert(ControlHandle controlHdl,ControlPartCode controlPartCode);
  54. pascal void actionFunctionHoriz(ControlHandle controlHdl,ControlPartCode controlPartCode);
  55. void doMoveScrollBox(ControlHandle controlHdl,SInt16 scrollDistance);
  56.  
  57.  
  58. //-----------------------------------------
  59. extern struct REALcontrol myControl;
  60.  
  61. /* The events this control can call:  */
  62. REALevent myEvents[] = {
  63.     { "MouseUp(X as Integer, Y as Integer)" }, //0
  64.     { "KeyDown(Key as String) as Boolean"}, //1
  65.     { "GotFocus()" }, //2
  66.     { "LostFocus()" }, //3
  67.     { "MouseDown(X as Integer, Y as Integer) as Boolean" }, //4
  68.     { "Paint(g as Graphics)" }, //5
  69.     { "MouseDrag(X as Integer, Y as Integer)" }, //6
  70.     { "VScrollChanged()" }, //7
  71.     { "HScrollChanged()" } //8
  72. };
  73.  
  74. /* The properties stored in each control instance.  Those which are to be accessible
  75.     by the user are declared at the REALproperty myProperties section at the bottom. */
  76. struct myData
  77. {
  78.     Boolean enabled;
  79.     //Boolean    value;
  80.     REALpicture backdrop;
  81.     Boolean readonly;
  82.     Boolean accepttabs;
  83.     REALstring text;
  84.     Boolean havefocus;
  85.     REALgraphics graphics;
  86.     ControlHandle vscroll;
  87.     ControlHandle hscroll;
  88.     Boolean usevscroll;
  89.     Boolean usehscroll;
  90.     SInt16    vmin;
  91.     SInt16    vmax;
  92.     SInt16    vval;
  93.     SInt16    hmin;
  94.     SInt16    hmax;
  95.     SInt16    hval;
  96.     Boolean hasframe;
  97.         
  98.     //private properties
  99.     Boolean invscroll;
  100.     Boolean inhscroll;
  101. };
  102.  
  103.  
  104. /*   CONTROL BEHAVIOR FUNCTIONS
  105. The following functions are called at various times by RB.
  106. You have to declare which behavior functions to use at the
  107. REALcontrolBehaviour myBehaviour = {...}
  108. section at the bottom.
  109.  
  110. To access the control instance's properties in these (or any) functions,
  111. you need to add this line.
  112.     ControlData(myControl, instance, myData, data);
  113. You can then access a property like so:
  114.     data->havefocus=true;
  115. */
  116.  
  117.  
  118. /*     Init (constructor) function (called only once).
  119.         A good place to set the default values for your properties. */
  120. static void myInit(REALcontrolInstance instance)
  121. {
  122.     
  123.     ControlData(myControl, instance, myData, data);
  124.     data->enabled = true;
  125.     //data->value = false;
  126.     data->backdrop = nil;
  127.     data->readonly = false;
  128.     data->accepttabs = false;
  129.     data->text=nil;
  130.     data->havefocus=false;
  131.     data->vscroll=nil;
  132.     data->hscroll=nil;
  133.     data->usevscroll=true;
  134.     data->usehscroll=true;
  135.     
  136.     data->vmax=10;
  137.     data->hmax=10;
  138.     
  139.     data->hasframe=true;
  140.     
  141.     //internal
  142.     data->invscroll=false;
  143.     data->inhscroll=false;
  144.  
  145. }
  146.  
  147. /* Open function (called *before* the instance's open event). At this point, the 
  148.     control's window has been created and is available to you. (but maybe not for 68k) */
  149. static void myOpen(REALcontrolInstance instance)
  150. {    
  151.     //Check if AppearanceLib is available:
  152.     SInt32    feature;
  153.     if (!Gestalt(gestaltAppearanceAttr, &feature))
  154.     {
  155.         gHasAppearance = true;
  156.     }
  157.  
  158.     if (notinIDE(instance)) {        
  159.         ControlData(myControl, instance, myData, data);
  160.         //SysBeep(30);
  161.         if (data->usevscroll)
  162.         {
  163.             CreateVScroll(instance);
  164.         }
  165.         if (data->usehscroll)
  166.         {
  167.             CreateHScroll(instance);
  168.         }
  169.  
  170.         gHaveOpened=true;
  171.  
  172.     }
  173. }
  174.  
  175. /* Close window function */
  176. static void myClose(REALcontrolInstance instance)
  177. {
  178.   ControlData(myControl, instance, myData, data);
  179.     //SysBeep(30);
  180.   if (notinIDE(instance))
  181.   {
  182.     if (data->usevscroll)
  183.     {
  184.         DisposeControl(data->vscroll);
  185.         data->vscroll=nil;
  186.     }
  187.     if (data->usehscroll)
  188.     {
  189.         DisposeControl(data->hscroll);
  190.         data->hscroll=nil;
  191.     }
  192.   }
  193.   data->havefocus=false;
  194.   gHaveOpened=false;
  195. }
  196.  
  197. /* Dispose (destructor) function.  Clean up memory. */
  198. static void myDispose(REALcontrolInstance instance)
  199. {               
  200. }
  201.  
  202. /* Called during Idle events.   */
  203. static void myIdle(REALcontrolInstance instance)
  204. {
  205.  
  206.     /*
  207.     //The code here was designed to disable the scrollbars when the
  208.     //window becomes inactive, but it does not work well.
  209.  
  210.     OSErr                myerr;
  211.     REALwindow            win=nil;
  212.     WindowPtr            winhand=nil;
  213.     ProcessSerialNumber    curproc;
  214.     ProcessSerialNumber frontproc;
  215.     Boolean                sameproc=false;
  216.     //Boolean                refreshcontrols=false;
  217.     
  218.     win=REALGetControlWindow(instance);
  219.     winhand=REALGetWindowHandle(win);
  220.     
  221.     ControlData(myControl, instance, myData, data);
  222.  
  223.     if (win)
  224.     {
  225.         if (data->enabled)
  226.         {
  227.             myerr=GetFrontProcess(&frontproc);
  228.             myerr=GetCurrentProcess(&curproc);
  229.             SameProcess(&frontproc,&curproc,&sameproc);
  230.             if ( (winhand != FrontWindow()) || (!sameproc)  )
  231.             {
  232.                 //REALSelectGraphics(REALGetControlGraphics(instance));
  233.                 //disable the scrollbars...
  234.                 if (data->usevscroll)
  235.                 {
  236.                     myerr= DeactivateControl(data->vscroll);
  237.                     //  SetControlMaximum(data->vscroll,GetControlMinimum(data->vscroll));
  238.                     //  Draw1Control (data->vscroll);
  239.                 }
  240.                 if (data->usehscroll)
  241.                 {
  242.                     myerr= DeactivateControl(data->hscroll);
  243.                     //  SetControlMaximum(data->hscroll,GetControlMinimum(data->hscroll));
  244.                     //  Draw1Control (data->hscroll);
  245.                 }
  246.                 data->enabled=false;
  247.             }
  248.         }
  249.         else
  250.         {
  251.             myerr=GetFrontProcess(&frontproc);
  252.             myerr=GetCurrentProcess(&curproc);
  253.             SameProcess(&frontproc,&curproc,&sameproc);
  254.             if ( (winhand == FrontWindow()) && (sameproc) )
  255.             {
  256.                 //REALSelectGraphics(REALGetControlGraphics(instance));
  257.                 if (data->usevscroll)
  258.                 {
  259.                     myerr= ActivateControl(data->vscroll);
  260.                     //  SetControlMaximum(data->vscroll,data->vmax);
  261.                     //  Draw1Control (data->vscroll);
  262.                 }
  263.                 if (data->usehscroll)
  264.                 {
  265.                     myerr= ActivateControl(data->hscroll);
  266.                     //  SetControlMaximum(data->hscroll,data->hmax);
  267.                     //  Draw1Control (data->hscroll);
  268.                 }
  269.                 data->enabled=true;
  270.             }
  271.         }
  272.     }
  273.     */
  274. }
  275.  
  276. /* GotFocus: This function will be called if you set the control to accept
  277.     the focus by setting the REALcontrolAcceptFocus flag at the REALControl
  278.     section below.  It will not be called at mousedown (see how to setfocus there).
  279.     You might want to keep a data->havefocus boolean property like I am doing. */
  280. static void myGotFocus(REALcontrolInstance instance)
  281. {
  282.     //SysBeep(30);
  283.     ControlData(myControl, instance, myData, data);
  284.     if (!(data->havefocus))
  285.     {
  286.         //Call GotFocus Event:
  287.         void (*fp)(REALcontrolInstance instance);
  288.         fp = (void (*)(REALcontrolInstance instance)) REALGetEventInstance(instance, &myEvents[2]);
  289.                 if ((fp) && (data->enabled))
  290.         {
  291.             fp(instance);
  292.         }
  293.         data->havefocus=true;
  294.     }
  295. }
  296.  
  297. /* LostFocus called if REALcontrolAcceptFocus flag set. */
  298. static void myLostFocus(REALcontrolInstance instance)
  299. {
  300.     ControlData(myControl, instance, myData, data);
  301.     if (data->havefocus)
  302.     {
  303.         //Call LostFocus Event:
  304.         void (*fp)(REALcontrolInstance instance);
  305.         fp = (void (*)(REALcontrolInstance instance)) REALGetEventInstance(instance, &myEvents[3]);
  306.                 if ((fp) && (data->enabled))
  307.         {
  308.             fp(instance);
  309.         }
  310.         data->havefocus=false;
  311.     }
  312. }
  313.  
  314.  
  315. /* The Paint or Refresh function.  This is where you draw your control. */
  316. static void myDraw(REALcontrolInstance instance)
  317. {
  318.  
  319.     Rect            r;
  320.     Rect            r2;
  321.     Rect            r3;
  322.     REALgraphics     g;
  323.     
  324.     ControlData(myControl, instance, myData, data);
  325.  
  326.     //Draw my scrollbars if necessary.
  327.     //REALSelectGraphics(REALGetControlGraphics(instance));
  328.     REALGetControlBounds(instance, &r2);
  329.     
  330.     if ((data->vscroll) && (data->usevscroll) && (GetControlMaximum(data->vscroll) > GetControlMinimum(data->vscroll)))
  331.     {
  332.         Draw1Control (data->vscroll);
  333.     }
  334.     if ((data->hscroll) && (data->usehscroll) && (GetControlMaximum(data->hscroll) > GetControlMinimum(data->hscroll)))
  335.     {
  336.         Draw1Control (data->hscroll);
  337.     }
  338.     
  339.     r3.left=r2.left+1;
  340.     r3.right=r2.right-1;
  341.     r3.top=r2.top+1;
  342.     r3.bottom=r2.bottom-1;
  343.     
  344.     if (data->hasframe) {
  345.         if (gHasAppearance) {
  346.             //r3.left=r3.left+1;
  347.             //r3.right=r3.right-1;
  348.             //r3.top=r3.top+1;
  349.             //r3.bottom=r3.bottom-1;
  350.             DrawThemeEditTextFrame(&r3,1);
  351.         } else {
  352.             FrameRect(&r3);
  353.         }
  354.     }
  355.  
  356.  
  357.     //ClipRect ensure any drawing done by the control instance
  358.     //   doesn't spill outside its borders.
  359.     MyControlRect(instance, &r);
  360.     g=REALGetControlGraphics(instance);
  361.     REALSelectGraphics(g);
  362.     ClipRect(&r);
  363.  
  364.     if (data->backdrop)
  365.     {
  366.         if (data->hasframe)
  367.         {
  368.             r.left=r.left+1;
  369.             r.top=r.top+1;
  370.             r.bottom=r.bottom-1;
  371.             r.right=r.right-1;
  372.         }
  373.         REALDrawPicturePrimitive(data->backdrop, &r, 1); //1=transparent
  374.     }
  375.  
  376.     //Call my Paint(g) Event:
  377.     void (*fp)(REALcontrolInstance instance, REALgraphics);
  378.     fp = (void (*)(REALcontrolInstance instance, REALgraphics)) REALGetEventInstance(instance, &myEvents[5]);        
  379.     if ((fp) && (data->enabled))
  380.     {
  381.         fp(instance, REALGetControlGraphics(instance));
  382.     }
  383.  
  384. }
  385.  
  386.  
  387. /* MouseDown - return true to allow the mousedrag and mouseup functions to be called. */
  388. static Boolean myDoMouseDown(REALcontrolInstance instance, int x, int y, int modifiers)
  389. {
  390.     Rect            r;
  391.     Point            where;
  392.  
  393.     ControlData(myControl, instance, myData, data);
  394.     REALGetControlBounds(instance, &r);
  395.     
  396.     //If cursor hit a scrollbar, handle that and go ahead and return true so the focus isn't set.
  397.     where.h=(short) x;
  398.     where.v=(short) y;
  399.     if ((x>r.right-16) && (data->vscroll) && (data->usevscroll) && (GetControlMaximum(data->vscroll) > GetControlMinimum(data->vscroll)))
  400.     {
  401.             data->invscroll=true;
  402.             TrackControl(data->vscroll,where,(ControlActionUPP) -1);
  403.             return true;
  404.     }
  405.     if ((y>r.bottom-16) && (data->hscroll) && (data->usehscroll) && (GetControlMaximum(data->hscroll) > GetControlMinimum(data->hscroll)))
  406.     {
  407.             data->inhscroll=true;
  408.             TrackControl(data->hscroll,where,(ControlActionUPP) -1);
  409.             return true;
  410.     }
  411.     
  412.     //OK, set the focus if necessary.
  413.     MyControlRect(instance, &r);
  414.     if (!(data->havefocus))
  415.     {
  416.         //data->havefocus=true;
  417.         SetFocus(instance);
  418.         data->havefocus=true;
  419.     }
  420.  
  421.     //Then call the MouseDown(x,y) Event (return true if it returns true):
  422.     Boolean (*fp)(REALcontrolInstance instance, int, int);
  423.     fp = (Boolean (*)(REALcontrolInstance instance, int, int)) REALGetEventInstance(instance, &myEvents[4]);        
  424.     if ((fp) && (data->enabled))
  425.     {
  426.         return fp(instance,x-r.left,y-r.top);
  427.     }
  428.         
  429.     return false;
  430. }
  431.  
  432.  
  433. /* MouseDrag function */
  434. static void myMouseDrag(REALcontrolInstance instance, int x, int y)
  435. {
  436.     Rect        r;
  437.     //Point        where;
  438.     //SInt16        myval;
  439.     
  440.     ControlData(myControl, instance, myData, data);        
  441.  
  442.     /*
  443.     //The ScrollChanged events cannot be called while scrolling (draglib takes over)
  444.     
  445.     //Keep handling the scrollbars if necessary:
  446.     where.h=(short) x;
  447.     where.v=(short) y;
  448.     if (data->invscroll)
  449.     {
  450.         TrackControl(data->vscroll,where,(ControlActionUPP) -1);
  451.         
  452.         //Call VScrollChanged event if necessary:
  453.         myval = GetControlValue(data->vscroll);
  454.         if (myval != data->vval)
  455.         {
  456.             data->vval = myval;
  457.         
  458.             void (*fp)(REALcontrolInstance instance);
  459.             fp = (void (*)(REALcontrolInstance instance)) REALGetEventInstance(instance, &myEvents[7]);
  460.                     if (fp)
  461.             {
  462.                 fp(instance);
  463.             }
  464.         }
  465.         return;
  466.     }
  467.     if (data->inhscroll)
  468.     {
  469.         TrackControl(data->hscroll,where,(ControlActionUPP) -1);
  470.                 
  471.         //Call HScrollChanged event if necessary:
  472.         myval = GetControlValue(data->hscroll);
  473.         if (myval != data->hval)
  474.         {
  475.             data->hval = myval;
  476.         
  477.             void (*fp)(REALcontrolInstance instance);
  478.             fp = (void (*)(REALcontrolInstance instance)) REALGetEventInstance(instance, &myEvents[8]);
  479.                     if (fp)
  480.             {
  481.                 fp(instance);
  482.             }
  483.         }
  484.         return;
  485.     }
  486.     */
  487.     
  488.     //Call the MouseDrag event:
  489.     MyControlRect(instance, &r);
  490.     void (*fp)(REALcontrolInstance instance, int, int);
  491.     fp = (void (*)(REALcontrolInstance instance, int, int)) REALGetEventInstance(instance, &myEvents[6]);        
  492.     if ((fp) && (data->enabled))
  493.     {
  494.         fp(instance,x-r.left,y-r.top);
  495.     }
  496. }
  497.  
  498. /* MouseUp */
  499. static void myDoMouseUp(REALcontrolInstance instance, int x, int y)
  500. {
  501.     Rect    r;
  502.     SInt16        myval;
  503.     
  504.     //Stop tracking the scrollbars.
  505.     ControlData(myControl, instance, myData, data);
  506.     if (data->invscroll)
  507.     {
  508.         //Call VScrollChanged event if necessary:
  509.         myval = GetControlValue(data->vscroll);
  510.         if (myval != data->vval)
  511.         {
  512.             data->vval = myval;
  513.         
  514.             void (*fp)(REALcontrolInstance instance);
  515.             fp = (void (*)(REALcontrolInstance instance)) REALGetEventInstance(instance, &myEvents[7]);
  516.                     if (fp)
  517.             {
  518.                 fp(instance);
  519.             }
  520.         }
  521.         
  522.         data->invscroll=false;
  523.         return;
  524.     }
  525.     if (data->inhscroll)
  526.     {
  527.         //Call HScrollChanged event if necessary:
  528.         myval = GetControlValue(data->hscroll);
  529.         if (myval != data->hval)
  530.         {
  531.             data->hval = myval;
  532.         
  533.             void (*fp)(REALcontrolInstance instance);
  534.             fp = (void (*)(REALcontrolInstance instance)) REALGetEventInstance(instance, &myEvents[8]);
  535.                     if (fp)
  536.             {
  537.                 fp(instance);
  538.             }
  539.         }
  540.         
  541.         data->inhscroll=false;
  542.         return;
  543.     }
  544.  
  545.     //Call the mouseup event:
  546.     MyControlRect(instance, &r);
  547.     void (*fp)(REALcontrolInstance instance, int, int);
  548.     fp = (void (*)(REALcontrolInstance instance, int, int)) REALGetEventInstance(instance, &myEvents[0]);        
  549.     if ((fp) && (data->enabled))
  550.     {
  551.         fp(instance,x-r.left,y-r.top);
  552.     }
  553. }
  554.  
  555.  
  556. /* The KeyDown event.  This is only called if the control has the focus, and
  557.         it has to be declared as a REALproc in the control behavior definition section. */
  558. static Boolean myDoKeyDown(REALcontrolInstance instance, int charCode, int keyCode, int modifiers)
  559. {
  560.     const char mychar=charCode;
  561.     REALstring thechar;
  562.     
  563.     //If you don't do this the user won't be able to use the menu shortcuts.    
  564.     if (modifiers & cmdKey) //bitwiseand modifiers & cmdKey
  565.     {
  566.         return false;
  567.     }
  568.     
  569.     //I tried to provide the option of stopping the control from losing focus when
  570.     //  the tab key is pressed, but it doesn't work.
  571.     ControlData(myControl, instance, myData, data);
  572.     if ((charCode==9) && !(data->accepttabs))
  573.     {
  574.            return false;
  575.     }
  576.  
  577.     //Call the KeyDown(key) event:
  578.     thechar=REALBuildString(&mychar,1);
  579.     Boolean (*fp)(REALcontrolInstance instance, REALstring);
  580.     fp = (Boolean (*)(REALcontrolInstance instance, REALstring)) REALGetEventInstance(instance, &myEvents[1]);
  581.     if ((fp) && (data->enabled) && !(data->readonly))
  582.     {
  583.         return fp(instance, thechar);
  584.     }
  585.        return false;
  586. }
  587.  
  588.  
  589. /*
  590. CONTROL METHODS (which are accessible by the user)
  591.     These are the custom methods that can be called from your control by the user.
  592.     See Thomas Tempelmann's example plugins for more examples of method functions.
  593.     
  594.     Declare them below as REALprocs.
  595. */
  596.  
  597. //Graphics is actually a method, not a property.  It returns the control's REALgraphics.
  598. static REALgraphics mygraphics(REALcontrolInstance instance)
  599. {
  600.     Rect    r;
  601.     REALgraphics g;
  602.  
  603.     REALGetControlBounds(instance, &r);
  604.     g=REALGetControlGraphics(instance);
  605.     REALSelectGraphics(g);
  606.     MyControlRect(instance, &r);
  607.  
  608.     //This keeps any drawing to the graphics from spilling outside its borders (or
  609.     //   onto the scrollbars)
  610.     ClipRect(&r);
  611.     
  612.     return g;
  613. }
  614.  
  615.  
  616.  
  617. /*   CUSTOM GETTER & SETTER FUNCTIONS     
  618.  
  619. General form of getter & setter functions:
  620.  
  621. my_property_type theGetter(REALcontrolInstance instance, my_property_type param);
  622. void theSetter(REALcontrolInstance instance, my_property_type param, my_property_type theValue);
  623.  
  624. Remember they are called in the IDE, too.
  625.  
  626. */
  627. static SInt16 vvalGetter(REALcontrolInstance instance, long param)
  628. {
  629.     ControlData(myControl, instance, myData, data);
  630.     if (notinIDE(instance))
  631.     {
  632.         return GetControlValue(data->vscroll);
  633.     } else {
  634.         return data->vval;
  635.     }
  636. }
  637. static SInt16 vminGetter(REALcontrolInstance instance, long param)
  638. {
  639.     ControlData(myControl, instance, myData, data);
  640.     if (notinIDE(instance))
  641.     {
  642.         return GetControlMinimum(data->vscroll);
  643.     } else {
  644.         return data->vmin;
  645.     }
  646. }
  647. static SInt16 vmaxGetter(REALcontrolInstance instance, long param)
  648. {
  649.     ControlData(myControl, instance, myData, data);
  650.     if (notinIDE(instance))
  651.     {
  652.         return GetControlMaximum(data->vscroll);
  653.     } else {
  654.         return data->vmax;
  655.     }
  656. }
  657.  
  658. static SInt16 hvalGetter(REALcontrolInstance instance, long param)
  659. {
  660.     ControlData(myControl, instance, myData, data);
  661.     if (notinIDE(instance))
  662.     {
  663.         return GetControlValue(data->hscroll);
  664.     } else {
  665.         return data->hval;
  666.     }
  667. }
  668. static SInt16 hminGetter(REALcontrolInstance instance, long param)
  669. {
  670.     ControlData(myControl, instance, myData, data);
  671.     if (notinIDE(instance))
  672.     {
  673.         return GetControlMinimum(data->hscroll);
  674.     } else {
  675.         return data->hmin;
  676.     }
  677. }
  678. static SInt16 hmaxGetter(REALcontrolInstance instance, long param)
  679. {
  680.     ControlData(myControl, instance, myData, data);
  681.     if (notinIDE(instance))
  682.     {
  683.         return GetControlMaximum(data->hscroll);
  684.     } else {
  685.         return data->hmax;
  686.     }
  687. }
  688.  
  689. static void    vvalSetter(REALcontrolInstance instance, long param, SInt16 theValue)
  690. {
  691.     ControlData(myControl, instance, myData, data);
  692.     if (theValue == data->vval)
  693.     {return;}
  694.  
  695.     data->vval=theValue;
  696.  
  697.     if (notinIDE(instance))
  698.     {
  699.         SetControlValue(data->vscroll,theValue);    
  700.         if (gHaveOpened)
  701.         {
  702.             //Call the VScrollChanged Event:
  703.             void (*fp)(REALcontrolInstance instance);
  704.             fp = (void (*)(REALcontrolInstance instance)) REALGetEventInstance(instance, &myEvents[7]);
  705.             if (fp)
  706.             {
  707.                 fp(instance);
  708.             }
  709.         }
  710.     }        
  711. }
  712. static void    vminSetter(REALcontrolInstance instance, long param, SInt16 theValue)
  713. {
  714.     ControlData(myControl, instance, myData, data);
  715.     if (notinIDE(instance))
  716.     {
  717.         SetControlMinimum(data->vscroll,theValue);
  718.     }
  719.     data->vmin=theValue;
  720. }
  721. static void    vmaxSetter(REALcontrolInstance instance, long param, SInt16 theValue)
  722. {
  723.     ControlData(myControl, instance, myData, data);
  724.     if (notinIDE(instance))
  725.     {
  726.         SetControlMaximum(data->vscroll,theValue);
  727.     }
  728.     data->vmax=theValue;
  729. }
  730.  
  731. static void    hvalSetter(REALcontrolInstance instance, long param, SInt16 theValue)
  732. {
  733.     ControlData(myControl, instance, myData, data);
  734.     if (theValue == data->hval)
  735.     {return;}
  736.  
  737.     data->hval=theValue;
  738.  
  739.     if (notinIDE(instance))
  740.     {    
  741.         SetControlValue(data->hscroll,theValue);
  742.         if (gHaveOpened)
  743.         {    
  744.             //Call the HScrollChanged event:
  745.             void (*fp)(REALcontrolInstance instance);
  746.             fp = (void (*)(REALcontrolInstance instance)) REALGetEventInstance(instance, &myEvents[8]);
  747.             if (fp)
  748.             {
  749.                 fp(instance);
  750.             }
  751.         }
  752.     }
  753. }
  754. static void    hminSetter(REALcontrolInstance instance, long param, SInt16 theValue)
  755. {
  756.     ControlData(myControl, instance, myData, data);
  757.     if (notinIDE(instance))
  758.     {
  759.         SetControlMinimum(data->hscroll,theValue);
  760.     }
  761.     data->hmin=theValue;
  762. }
  763. static void    hmaxSetter(REALcontrolInstance instance, long param, SInt16 theValue)
  764. {
  765.     ControlData(myControl, instance, myData, data);
  766.     if (notinIDE(instance))
  767.     {
  768.         SetControlMaximum(data->hscroll,theValue);
  769.     }
  770.     data->hmax=theValue;
  771. }
  772.  
  773.  
  774.  
  775.  
  776. /*
  777. CONTROL DECLARATIONS
  778.     These are needed in every plugin control source code.  Declare which properties and
  779.     methods are accessible by the user (and how they are accessed).  Declare the control
  780.     behavior and structure.
  781. */
  782.  
  783. REALproperty myProperties[] = {
  784.     //{"Appearance", "Enabled", "Boolean", REALpropInvalidate, REALstandardGetter, REALstandardSetter, FieldOffset(myData, enabled)},
  785.     //{"Appearance", "Value", "Boolean", REALpropInvalidate,REALstandardGetter, REALstandardSetter, FieldOffset(myData, value)},
  786.     {"Appearance", "Backdrop", "Picture", REALpropInvalidate, REALstandardGetter, REALstandardSetter, FieldOffset(myData, backdrop)},
  787.     {"Appearance", "ReadOnly", "Boolean", REALpropInvalidate, REALstandardGetter, REALstandardSetter, FieldOffset(myData, readonly)},
  788.     {"Appearance", "AcceptTabs", "Boolean", REALpropInvalidate, REALstandardGetter, REALstandardSetter, FieldOffset(myData, accepttabs)},
  789.     {"Appearance", "Text", "String", REALpropInvalidate, REALstandardGetter, REALstandardSetter, FieldOffset(myData, text)},
  790.     {"Appearance", "HaveFocus", "Boolean", REALpropRuntimeOnly, REALstandardGetter, REALstandardSetter, FieldOffset(myData, havefocus)},
  791.     {"Appearance", "HasFrame", "Boolean", REALpropInvalidate, REALstandardGetter, REALstandardSetter, FieldOffset(myData, hasframe)},
  792.  
  793.  
  794.     // {"VerticalScrollBar", "VScrollHandle", "Integer", REALpropRuntimeOnly, REALstandardGetter, nil, FieldOffset(myData, vscroll)},
  795.     {"VerticalScrollBar", "UseVScrollBar", "Boolean", REALpropInvalidate, REALstandardGetter, REALstandardSetter, FieldOffset(myData, usevscroll)},
  796.     {"VerticalScrollBar", "VMinimum", "Integer", REALpropInvalidate, (REALproc) vminGetter, (REALproc) vminSetter, FieldOffset(myData, vmin)},
  797.     {"VerticalScrollBar", "VMaximum", "Integer", REALpropInvalidate, (REALproc) vmaxGetter, (REALproc) vmaxSetter, FieldOffset(myData, vmax)},
  798.     {"VerticalScrollBar", "VValue", "Integer", REALpropInvalidate, (REALproc) vvalGetter, (REALproc) vvalSetter, FieldOffset(myData, vval)},
  799.  
  800.     // {"HorizontalScrollBar", "HScrollHandle", "Integer", REALpropRuntimeOnly, REALstandardGetter, nil, FieldOffset(myData, hscroll)},
  801.     {"HorizontalScrollBar", "UseHScrollBar", "Boolean", REALpropInvalidate, REALstandardGetter, REALstandardSetter, FieldOffset(myData, usehscroll)},
  802.     {"HorizontalScrollBar", "HMinimum", "Integer", REALpropInvalidate, (REALproc) hminGetter, (REALproc) hminSetter, FieldOffset(myData, hmin)},
  803.     {"HorizontalScrollBar", "HMaximum", "Integer", REALpropInvalidate, (REALproc) hmaxGetter, (REALproc) hmaxSetter, FieldOffset(myData, hmax)},
  804.     {"HorizontalScrollBar", "HValue", "Integer", REALpropInvalidate, (REALproc) hvalGetter, (REALproc) hvalSetter, FieldOffset(myData, hval)}
  805.  
  806. };
  807.  
  808. REALmethodDefinition myMethods[] = {
  809.     { (REALproc) mygraphics, REALnoImplementation, "Graphics() as Graphics"}
  810. };
  811.  
  812. REALcontrolBehaviour myBehaviour = {
  813.     myInit,                //the init function
  814.     nil, //myDispose,    //the dispose function goes here
  815.     myDraw,                //the redraw function
  816.     myDoMouseDown,        
  817.     myMouseDrag,
  818.     myDoMouseUp,
  819.     myGotFocus, //gainedfocus
  820.     myLostFocus, //lostfocus
  821.     (REALproc) myDoKeyDown,  //keydown
  822.     myOpen, //open
  823.     myClose, //close
  824.     nil //myIdle //idle
  825. };
  826.  
  827. REALcontrol myControl = {
  828.     kCurrentREALControlVersion,
  829.     "KeyCanvas", //The default name of your control in the IDE
  830.     sizeof(myData),
  831.     REALenabledControl | REALcontrolAcceptFocus | REALcontrolFocusRing ,
  832.     /*
  833.     ##define REALcontrolAcceptFocus 1
  834.     ##define REALcontrolFocusRing 2
  835.     ##define REALinvisibleControl 4
  836.     ##define REALopaqueControl 8
  837.     ##define REALenabledControl 16
  838.     */
  839.     128,129, //Resource numbers for the pressed and unpressed pictures to use in the IDE toolbar
  840.     150,150, //default size of control when you drop it onto a window in the IDE
  841.     myProperties,
  842.     sizeof(myProperties) / sizeof(REALproperty),
  843.     myMethods,
  844.     sizeof(myMethods) / sizeof(REALmethodDefinition),
  845.     myEvents,
  846.     sizeof(myEvents) / sizeof(REALevent),
  847.     &myBehaviour
  848. };
  849.  
  850. void PluginEntry(void)
  851. {
  852.     REALRegisterControl(&myControl);
  853. }
  854.  
  855.  
  856.  
  857.  
  858. /* _________________________CUSTOM FUNCTIONS_______________________________ */
  859.  
  860.  
  861. //This function shrinks the control rectangle if scrollbars are being used.
  862. static void MyControlRect (REALcontrolInstance instance, Rect *rBounds)
  863. {
  864.     ControlData(myControl, instance, myData, data);
  865.     REALGetControlBounds(instance, rBounds);
  866.     
  867.     if ((data->vscroll) && (data->usevscroll) && (data->vmax > data->vmin))
  868.     {
  869.             rBounds->right=rBounds->right-16;
  870.     }
  871.     if ((data->hscroll) && (data->usehscroll) && (data->hmax > data->hmin))
  872.     {
  873.             rBounds->bottom=rBounds->bottom-16;
  874.     }
  875.     if (data->hasframe)
  876.     {
  877.         rBounds->top=rBounds->top+1;
  878.         rBounds->left=rBounds->left+1;
  879.     }
  880.  
  881. }
  882.  
  883. static Boolean notinIDE(REALcontrolInstance instance)
  884. {
  885.     REALwindow        win=nil;
  886.     WindowPtr        winhand=nil;
  887.  
  888.     win=REALGetControlWindow(instance);
  889.     if (win)
  890.     {
  891.         return true;
  892.     }
  893.     return false;
  894. }
  895.  
  896. static void CreateVScroll(REALcontrolInstance instance)
  897. {
  898.     Rect            r;
  899.     REALwindow        win=nil;
  900.     WindowPtr        winhand=nil;
  901.  
  902.     win=REALGetControlWindow(instance);
  903.     winhand=REALGetWindowHandle(win);
  904.     
  905.     if (!win)
  906.     {return;}
  907.     
  908.     ControlData(myControl, instance, myData, data);
  909.  
  910.     REALGetControlBounds(instance, &r);
  911.     r.left=r.right-16;
  912.  
  913.     //scrollBarProc=16 (standard scrollbar)
  914.     //kControlScrollBarProc=384 (appearance)
  915.     //kControlScrollBarLiveProc=386 (live scrollbar)
  916.     if (gHasAppearance) {
  917.         data->vscroll=NewControl(winhand,&r,"\p",true,data->vval,data->vmin,data->vmax,kControlScrollBarProc,0L);
  918.     } else {
  919.         data->vscroll=NewControl(winhand,&r,"\p",true,data->vval,data->vmin,data->vmax,scrollBarProc,0L);
  920.     }
  921.     actionFunctionVertUPP = NewControlActionProc((ProcPtr) actionFunctionVert);
  922.     SetControlAction(data->vscroll,actionFunctionVertUPP);
  923. }
  924.  
  925. static void CreateHScroll(REALcontrolInstance instance)
  926. {
  927.     Rect            r;
  928.     REALwindow        win=nil;
  929.     WindowPtr        winhand=nil;
  930.  
  931.     win=REALGetControlWindow(instance);
  932.     winhand=REALGetWindowHandle(win);
  933.  
  934.     if (!win)
  935.     {return;}
  936.     
  937.     ControlData(myControl, instance, myData, data);
  938.  
  939.     REALGetControlBounds(instance, &r);
  940.     r.top=r.bottom-16;
  941.     if (data->usevscroll)
  942.     {
  943.         r.right=r.right-16;
  944.     }
  945.     //scrollBarProc=16 (standard scrollbar)
  946.     //kControlScrollBarProc=384 (appearance)
  947.     //kControlScrollBarLiveProc=386 (live scrollbar)
  948.     if (gHasAppearance) {
  949.         data->hscroll=NewControl(winhand,&r,"\p",true,data->hval,data->hmin,data->hmax,kControlScrollBarProc,0L);
  950.     } else {
  951.         data->hscroll=NewControl(winhand,&r,"\p",true,data->hval,data->hmin,data->hmax,scrollBarProc,0L);
  952.     }
  953.     actionFunctionHorizUPP = NewControlActionProc((ProcPtr) actionFunctionHoriz);
  954.     SetControlAction(data->hscroll,actionFunctionHorizUPP);
  955. }
  956.  
  957. /*
  958.     ScrollBar callback functions (largely adapted from the Macintosh-C tutorial)
  959. */
  960.  
  961. /*  This is the vertical scrollbar callback function: */
  962. pascal void  actionFunctionVert(ControlHandle controlHdl,ControlPartCode controlPartCode)
  963. {
  964.     SInt16        scrollDistance, controlValue;
  965.  
  966.     if(controlPartCode != kControlIndicatorPart)
  967.     {            
  968.         switch(controlPartCode)
  969.         {
  970.             case kControlUpButtonPart:
  971.             case kControlDownButtonPart:
  972.                 scrollDistance = 2;
  973.                 break;
  974.  
  975.             case kControlPageUpPart:
  976.             case kControlPageDownPart:
  977.                 scrollDistance = 30;
  978.                 break;
  979.         }
  980.         
  981.         if((controlPartCode == kControlDownButtonPart) || 
  982.              (controlPartCode == kControlPageDownPart))
  983.             scrollDistance = -scrollDistance;
  984.  
  985.         controlValue = GetControlValue(controlHdl);
  986.         if(((controlValue == GetControlMaximum(controlHdl)) && scrollDistance < 0) || 
  987.              ((controlValue == GetControlMinimum(controlHdl)) && scrollDistance > 0))
  988.             return;
  989.  
  990.         doMoveScrollBox(controlHdl,scrollDistance);
  991.     }
  992.  
  993. }
  994.  
  995. /*  This is the horizontal scrollbar callback function: */
  996. pascal void  actionFunctionHoriz(ControlHandle controlHdl, ControlPartCode controlPartCode)
  997. {
  998.     SInt16        scrollDistance, controlValue;
  999.  
  1000.     if(controlPartCode != kControlIndicatorPart)
  1001.     {            
  1002.         switch(controlPartCode)
  1003.         {
  1004.             case kControlUpButtonPart:
  1005.             case kControlDownButtonPart:
  1006.                 scrollDistance = 2;
  1007.                 break;
  1008.  
  1009.             case kControlPageUpPart:
  1010.             case kControlPageDownPart:
  1011.                 scrollDistance = 30;
  1012.                 break;
  1013.         }
  1014.         
  1015.         if((controlPartCode == kControlDownButtonPart) || 
  1016.              (controlPartCode == kControlPageDownPart))
  1017.             scrollDistance = -scrollDistance;
  1018.  
  1019.         controlValue = GetControlValue(controlHdl);
  1020.         if(((controlValue == GetControlMaximum(controlHdl)) && scrollDistance < 0) || 
  1021.              ((controlValue == GetControlMinimum(controlHdl)) && scrollDistance > 0))
  1022.             return;
  1023.  
  1024.         doMoveScrollBox(controlHdl,scrollDistance);
  1025.     }
  1026.  
  1027. }
  1028.  
  1029. void doMoveScrollBox(ControlHandle controlHdl,SInt16 scrollDistance)
  1030. {
  1031.     SInt16    oldControlValue, controlValue, controlMax;
  1032.  
  1033.     oldControlValue = GetControlValue(controlHdl);
  1034.     controlMax = GetControlMaximum(controlHdl);
  1035.  
  1036.     controlValue = oldControlValue - scrollDistance;
  1037.     
  1038.     if(controlValue < 0)
  1039.         controlValue = 0;
  1040.     else if(controlValue > controlMax)
  1041.         controlValue = controlMax;
  1042.  
  1043.     SetControlValue(controlHdl,controlValue);
  1044.  
  1045. }
  1046.